
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

package com.hlkj.pay.app.adminuser.impl;

import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import com.hlkj.framework.common.pojo.CommonResult;
import com.hlkj.framework.common.pojo.LocalContext;
import com.hlkj.framework.common.provider.Aes256EncryptionProvider;
import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.pay.app.adminuser.IAdminUserLoginAppService;
import com.hlkj.pay.app.adminuser.IUserPermissionAppService;
import com.hlkj.pay.app.common.IAuthCodeService;
import com.hlkj.pay.app.common.IGeetestAppService;
import com.hlkj.pay.app.token.ITokenAuthService;
import com.hlkj.pay.common.AdminUserResultCode;
import com.hlkj.pay.common.CommonResultCode;
import com.hlkj.pay.common.constants.AdminUserConstant;
import com.hlkj.pay.dto.LocalAdminUserRequest;
import com.hlkj.pay.dto.admin.AdminUserDto;
import com.hlkj.pay.enums.AdminUserEnum;
import com.hlkj.pay.enums.AuthTokenEnum;
import com.hlkj.pay.enums.CommonEnum;
import com.hlkj.pay.service.admin.IAdminUserService;
import com.hlkj.pay.util.DesensitizedUtils;
import com.hlkj.pay.util.TokenUtils;
import com.hlkj.pay.vo.admin.req.user.AdminCommonUserLoginReq;
import com.hlkj.pay.vo.admin.req.user.AdminUserForgetPwdReq;
import com.hlkj.pay.vo.admin.req.user.AdminUserLoginReq;
import com.hlkj.pay.vo.admin.req.user.AdminUserPhoneLoginReq;
import com.hlkj.pay.vo.admin.resp.user.AdminUserAccountResp;
import com.hlkj.pay.vo.common.req.token.AuthMfaCheckTokenRequest;
import com.hlkj.pay.vo.common.req.token.PasswordTokenRequest;
import com.hlkj.pay.vo.common.req.token.PhoneTokenRequest;
import com.hlkj.pay.vo.common.resp.token.LoginTokenResp;
import com.hlkj.pay.vo.common.resp.token.OauthTokenResp;
import com.hlkj.pay.vo.common.resp.token.TokenInfoResp;

import cn.hutool.core.util.RandomUtil;
import jodd.util.StringPool;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @author HlpayTeam
 * @date 2024/09/10 14:50
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AdminUserLoginAppServiceImpl implements IAdminUserLoginAppService {

    private final ITokenAuthService tenantAuthService;

    private final IUserPermissionAppService userPermissionAppService;

    private final IAdminUserService userService;

    private final IGeetestAppService geetestAppService;

    private final IAuthCodeService authCodeService;

    private final Aes256EncryptionProvider aes256EncryptionProvider;

    @Override
    public CommonResult<LoginTokenResp> login(AdminUserLoginReq userLoginReq) {
        log.info("login userLoginReq:{}", JsonUtils.toJsonString(userLoginReq));
        try {
            CommonResult<Boolean> validate = geetestAppService.validate(userLoginReq.getVerification());
            if (!validate.isSuccess()) {
                return CommonResult.error(validate.getCode(), validate.getMsg());
            }
            // String appId =
            // WebFrameworkUtils.getRequest().getHeader(AdminConstant.APP_ID);
            PasswordTokenRequest passWordTokenDTO = new PasswordTokenRequest();
            passWordTokenDTO.setPassword(userLoginReq.getPwd());
            passWordTokenDTO.setUserName(userLoginReq.getAccount());
            // passWordTokenDTO.setAppId(appId);
            // passWordTokenDTO.setAppSecret(appSecret);
            CommonResult<OauthTokenResp> oauthTokenRespCommonResult = tenantAuthService.webUserToken(passWordTokenDTO);
            return processLogin(oauthTokenRespCommonResult, userLoginReq);
        }
        catch (Exception e) {
            e.printStackTrace();
            log.error("login error,message:{}", e.getMessage());
            return CommonResult.error(CommonResultCode.SERVICE_ERROR);
        }
    }

    @Override
    public CommonResult<LoginTokenResp> codeLogin(AdminUserPhoneLoginReq userLoginReq) {
        log.info("codeLogin userLoginReq:{}", JsonUtils.toJsonString(userLoginReq));
        try {
            PhoneTokenRequest phoneTokenRequest = new PhoneTokenRequest();
            phoneTokenRequest.setSmsCode(userLoginReq.getSmsCode());
            phoneTokenRequest.setPhone(userLoginReq.getPhone());
            CommonResult<OauthTokenResp> oauthTokenRespCommonResult = tenantAuthService.webUserToken(phoneTokenRequest);
            return processLogin(oauthTokenRespCommonResult, userLoginReq);
        }
        catch (Exception e) {
            log.error("codeLogin error,message:{}", e.getMessage());
            return CommonResult.error(CommonResultCode.SERVICE_ERROR);
        }
    }

    CommonResult<LoginTokenResp> processLogin(CommonResult<OauthTokenResp> oauthTokenRespCommonResult, AdminCommonUserLoginReq userLoginReq) {
        if (!oauthTokenRespCommonResult.isSuccess()) {
            OauthTokenResp data = oauthTokenRespCommonResult.getData();
            log.info("真实失败原因:{}", JsonUtils.toJsonString(oauthTokenRespCommonResult));
            CommonResult<LoginTokenResp> error = CommonResult.error(AdminUserResultCode.USER_PWD_ERROR);
            if (data != null) {
                LoginTokenResp loginTokenResp = new LoginTokenResp();
                loginTokenResp.setToken(data.getToken());
                loginTokenResp.setRefreshToken(data.getRefreshToken());
                loginTokenResp.setExpiresTime(data.getExpiresTime());
                loginTokenResp.setExpiresIn(data.getExpiresIn());
                loginTokenResp.setMfaLoginType(data.getMfaLoginType());
                loginTokenResp.setErrorNum(data.getErrorNum());
                error.setData(loginTokenResp);
                return error;
            }
            else {
                return error;
            }
        }

        OauthTokenResp data = oauthTokenRespCommonResult.getData();
        TokenInfoResp resultData = TokenUtils.parseToken(data.getToken());
        // 设置线程信息 login 不要进入token 拦截器
        LocalAdminUserRequest userRequest = new LocalAdminUserRequest();
        // userRequest.setTenantId(resultData.getTenantId());
        userRequest.setUserId(resultData.getUserId());
        log.info("login user info:{}", JsonUtils.toJsonString(userRequest));
        LocalContext.set(userRequest);
        CommonResult<AdminUserAccountResp> userAccountRespCommonResult = userPermissionAppService.login(userLoginReq);
        AdminUserAccountResp adminUserAccountResp = userAccountRespCommonResult.getData();
        LoginTokenResp loginTokenResp = new LoginTokenResp();
        String phone = adminUserAccountResp.getPhone();
        String email = adminUserAccountResp.getEmail();
        if (StringUtils.hasText(email)) {
            try {
                email = aes256EncryptionProvider.decrypt(email);
            }
            catch (Exception e) {
                log.error("decrypt error:{}", email);
            }
            try {
                phone = aes256EncryptionProvider.decrypt(phone);
            }
            catch (Exception e) {
                log.error("phone error:{}", phone);
            }
            phone = DesensitizedUtils.desValue(phone, 3, 4, StringPool.ASTERISK);
            int index = email.length() - email.lastIndexOf(StringPool.AT);
            email = DesensitizedUtils.desValue(email, 2, index, StringPool.ASTERISK);
            loginTokenResp.setEmail(email);
        }
        loginTokenResp.setPhone(phone);
        loginTokenResp.setToken(data.getToken());
        loginTokenResp.setRefreshToken(data.getRefreshToken());
        loginTokenResp.setExpiresTime(data.getExpiresTime());
        loginTokenResp.setExpiresIn(data.getExpiresIn());
        loginTokenResp.setMfaLoginType(data.getMfaLoginType());
        loginTokenResp.setErrorNum(data.getErrorNum());
        loginTokenResp.setFirstLogin(adminUserAccountResp.isFristLogin());
        return CommonResult.success(loginTokenResp);
    }

    @Override
    public CommonResult<Void> logout() {
        // tenantAuthFeignClient.expireToken()
        userPermissionAppService.logout();
        return CommonResult.success(null);
    }

    @Override
    public CommonResult<OauthTokenResp> refreshToken(String refreshToken) {
        if (StringUtils.isEmpty(refreshToken)) {
            return CommonResult.error(CommonResultCode.TOKEN_PARAMETER_MISSING);
        }
        TokenInfoResp refreshTokenInfoResp = TokenUtils.parseToken(refreshToken);

        AuthTokenEnum.AUTH_TOKEN_TYPE authTokenType = AuthTokenEnum.AUTH_TOKEN_TYPE.from(refreshTokenInfoResp.getAuthTokenType());
        switch (authTokenType) {
            case ACCESS_TOKEN:
                return CommonResult.error(CommonResultCode.TOKEN_PARAMETER_ERROR);
        }
        CommonResult<OauthTokenResp> commonResult = tenantAuthService.refreshToken(refreshToken);
        if (!commonResult.isSuccess()) {
            return CommonResult.error(commonResult.getCode(), commonResult.getMsg());
        }
        OauthTokenResp data = commonResult.getData();
        Long expireTime = data.getExpiresTime();
        if (expireTime == null || System.currentTimeMillis() / 1000 > expireTime) {
            return CommonResult.error(CommonResultCode.TOKEN_PARAMETER_EXPIRE);
        }
        return commonResult;
    }

    @Override
    public CommonResult<OauthTokenResp> mfaLogin(String authCode) {
        AuthMfaCheckTokenRequest authMfaCheckTokenRequest = new AuthMfaCheckTokenRequest();
        authMfaCheckTokenRequest.setAuthCode(authCode);
        LocalAdminUserRequest localRequest = (LocalAdminUserRequest) LocalContext.get();
        authMfaCheckTokenRequest.setToken(localRequest.getAccessToken());
        return tenantAuthService.mfaCheckToken(authMfaCheckTokenRequest);
    }

    @Override
    public CommonResult<Void> forgetPwd(AdminUserForgetPwdReq adminUserForgetPwdReq) {
        log.info("forgetPwd adminUserForgetPwdReq:{}", JsonUtils.toJsonString(adminUserForgetPwdReq));
        try {
            CommonResult<Void> voidCommonResult = authCodeService.checkAuthCode(adminUserForgetPwdReq.getPhone(), AdminUserEnum.AdminAuthCodeEnum.ADMIN_AUTH_CODE_FORGET_PWD,
                    adminUserForgetPwdReq.getSmsCode());
            if (!voidCommonResult.isSuccess()) {
                return voidCommonResult;
            }
            if (!adminUserForgetPwdReq.getPwd().equals(adminUserForgetPwdReq.getPwdConfirm())) {
                return CommonResult.error(AdminUserResultCode.SECOND_PASSWORD_IS_INCONSISTENT);
            }
            try {
                AdminUserDto adminUserDto = userService.queryUserByPhone(adminUserForgetPwdReq.getPhone(), null);
                if (adminUserDto == null) {
                    return CommonResult.error(AdminUserResultCode.USER_DOES_NOT_EXIST);
                }
                String pwdEncrypt = aes256EncryptionProvider.encryptString(adminUserForgetPwdReq.getPwd());
                userService.updatePwd(adminUserDto.getId(), pwdEncrypt, CommonEnum.YES_NO_TYPE.NO);
            }
            catch (Exception e) {
                log.error("encrypt error:{}", e.getMessage(), e);
                return CommonResult.error(CommonResultCode.SERVICE_ERROR);
            }
            return CommonResult.success();
        }
        catch (Exception e) {
            log.error("forgetPwd error,message:{}", e.getMessage());
            return CommonResult.error(CommonResultCode.SERVICE_ERROR);
        }

    }

    /**
     * 密码明文
     * 
     * @return
     */
    String password() {
        String baseChar = RandomUtil.randomString(RandomUtil.BASE_CHAR_NUMBER, 4);
        String baseCharCase = RandomUtil.randomString(RandomUtil.BASE_CHAR.toUpperCase(), 1);
        String s1 = RandomUtil.randomString(AdminUserConstant.PWD_END_CHAR, 1);
        return baseChar + baseCharCase + s1;
    }

}
